﻿#pragma once
#include <bstring/bstrwrap.h>
#include "assert.h"
#include "elib/lib2.h"


namespace fne
{
	INT WINAPI ProcessNotifyLib(INT nMsg, DWORD dwParam1, DWORD dwParam2);
	INT WINAPI NotifySys(INT nMsg, DWORD dwParam1, DWORD dwParam2);

	template <typename T>
	auto& args_to_this(PMDATA_INF pArgInf)
	{
		return reinterpret_cast<T*&>(pArgInf[0].m_ppCompoundData[0]);
	}

	template <typename T>
	auto& args_to_other(PMDATA_INF pArgInf)
	{
		return reinterpret_cast<T*&>(pArgInf[1].m_ppCompoundData[0]);
	}

	template <typename T>
	auto& args_to_member(PMDATA_INF pArgInf, size_t index)
	{
		return reinterpret_cast<T&>(pArgInf[0].m_ppCompoundData[index]);
	}

	inline void* malloc(INT nSize)
	{
		const auto pMem = reinterpret_cast<void*>(NotifySys(NRS_MALLOC, nSize, 0));
		return pMem;
	}

	inline void free(void* p)
	{
		NotifySys(NRS_FREE_ARY, reinterpret_cast<DWORD>(p), 0);
	}

	inline CBString get_path(DWORD id)
	{
		char buf[0x256];
		NotifySys(NAS_GET_PATH, id, reinterpret_cast<DWORD>(buf));
		return buf;
	}

	inline char* clone_text(char* ps)
	{
		if (ps == nullptr || *ps == '\0')
			return nullptr;

		const INT nTextLen = strlen(ps);
		const auto pd = static_cast<char*>(malloc(nTextLen + 1));
		memcpy(pd, ps, nTextLen);
		pd[nTextLen] = '\0';
		return pd;
	}


	inline char* clone_text(char* ps, INT nTextLen)
	{
		if (nTextLen <= 0)
			return nullptr;

		auto pd = reinterpret_cast<char*>(malloc(nTextLen + 1));
		memcpy(pd, ps, nTextLen);
		pd[nTextLen] = '\0';
		return pd;
	}


	inline LPBYTE clone_bin(const void* pData, INT nDataSize)
	{
		if (nDataSize == 0)
			return nullptr;

		const auto pd = static_cast<LPBYTE>(malloc(sizeof(INT) * 2 + nDataSize));
		*reinterpret_cast<LPINT>(pd) = 1;
		*reinterpret_cast<LPINT>(pd + sizeof(INT)) = nDataSize;
		memcpy(pd + sizeof(INT) * 2, pData, nDataSize);
		return pd;
	}

	inline LPBYTE malloc_array(int nCount)
	{
		const auto p = static_cast<LPBYTE>(malloc(sizeof(INT) * (2 + nCount)));
		*reinterpret_cast<LPINT>(p) = 1;
		*reinterpret_cast<LPINT>(p + sizeof(INT)) = nCount;
		return p;
	}

	template <typename T>
	LPBYTE malloc_array(int nCount)
	{
		const auto p = static_cast<LPBYTE>(malloc(sizeof(T) * nCount + 8));
		*reinterpret_cast<LPINT>(p) = 1;
		*reinterpret_cast<LPINT>(p + 4) = nCount;
		return p;
	}

	template <typename T>
	void* copy_array(void* data, size_t size)
	{
		if (!data)
			return nullptr;
		const auto p = reinterpret_cast<size_t*>(malloc_array<T>(size));
		memcpy(p + 2, data, sizeof(T) * size);
		return p;
	}

	inline void free_array(PMDATA_INF pArgInf)
	{
		NotifySys(NRS_FREE_ARY, pArgInf->m_dtDataType, reinterpret_cast<DWORD>(*pArgInf->m_ppAryData));
	}

	inline size_t array_size(void* array)
	{
		assert(array);
		return *reinterpret_cast<size_t*>(reinterpret_cast<uintptr_t>(array) + 4);
	}

	template <typename T>
	T& array_at(void* array, size_t index)
	{
		assert(array);
		return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(array) + 8 + sizeof(T) * index);
	}


	inline void report_error(char* szErrText)
	{
		NotifySys(NRS_RUNTIME_ERR, reinterpret_cast<DWORD>(szErrText), 0);
	}


	inline BOOL is_debug(char* szErrText)
	{
		return NotifySys(NRS_GET_PRG_TYPE, reinterpret_cast<DWORD>(szErrText), 0) == PT_DEBUG_RUN_VER;
	}

	//返回数组的数据部分首地址和成员数目
	inline LPBYTE get_array_element_inf(void* pAryData, LPINT pnElementCount)
	{
		auto pn_data = static_cast<LPINT>(pAryData);
		INT count = *pn_data++; //获取维数
		INT nElementCount = 1; //数组元素数量
		while (count > 0)
		{
			nElementCount *= *pn_data++;
			count--;
		}
		
		if (pnElementCount != nullptr)
			*pnElementCount = nElementCount;
		return reinterpret_cast<LPBYTE>(pn_data);
	}

	void append_to_binary(PMDATA_INF pArgInf, CBString& out);
	void append_to_string(PMDATA_INF pArgInf, CBString& out);
	CBString to_binary(PMDATA_INF pArgInf);
	CBString to_string(PMDATA_INF pArgInf);
	CBString to_string(int val);
	CBString to_string(float val);
	CBString to_string(double val);
	CBString to_string(long long val);
}
